ANDROID: fuse-bpf: Fix readdir for getdents

If you call getdents with a buffer size less than a page,
entries can be skipped. This correctly sets the point to continue from.

Bug: 325550828
Test: getdents with low buffer size
Signed-off-by: Daniel Rosenberg <drosen@google.com>
(cherry picked from https://android-review.googlesource.com/q/commit:506cf3f0742432c1995117f83b2528a23944989b)
Merged-In: I324e7e815d31742bd4e2d70c5d07c2b09a67a7c2
Change-Id: I324e7e815d31742bd4e2d70c5d07c2b09a67a7c2
diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 0bc637d..1862f27 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -2332,8 +2332,11 @@
 	return true;
 }
 
-static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx)
+static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx,
+		loff_t next_offset)
 {
+	char *buffstart = buf;
+
 	while (nbytes >= FUSE_NAME_OFFSET) {
 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
@@ -2347,12 +2350,18 @@
 
 		ctx->pos = dirent->off;
 		if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
-				dirent->type))
-			break;
+				dirent->type)) {
+			// If we can't make any progress, user buffer is too small
+			if (buf == buffstart)
+				return -EINVAL;
+			else
+				return 0;
+		}
 
 		buf += reclen;
 		nbytes -= reclen;
 	}
+	ctx->pos = next_offset;
 
 	return 0;
 }
@@ -2399,13 +2408,12 @@
 	struct file *backing_dir = ff->backing_file;
 	int err = 0;
 
-	err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx);
+	err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx, fro->offset);
 	*force_again = !!fro->again;
 	if (*force_again && !*allow_force)
 		err = -EINVAL;
 
-	ctx->pos = fro->offset;
-	backing_dir->f_pos = fro->offset;
+	backing_dir->f_pos = ctx->pos;
 
 	free_page((unsigned long) fa->out_args[1].value);
 	return ERR_PTR(err);